package com.tools.web.filter.gateway;

import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisClusterPlus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.Set;

/**
 * 使用 JedisClusterPlus 客户端
 * 操作集群 Redis 来实现网关过滤器
 * */
@Note("使用 JedisClusterPlus 客户端操作集群 Redis 来实现网关过滤器")
public final class JedisClusterPlusGetawayFilter extends GetawayFilter {

    @Note("JedisClusterPlus 操作集群 Redis 的客户端实例")
    private final JedisClusterPlus cache;

    @Note("日志输出实例")
    private static final Logger LOGGER = LoggerFactory.getLogger(JedisClusterPlusGetawayFilter.class);

    @Note("是否关闭代理服务器白名单功能，让所有请求可以绕过代理直接请求服务器。默认关闭")
    private boolean openAllRequest = false;

    @Note("是否封闭服务器的所有接口，阻止所有请求访问。默认关闭")
    private boolean disabledAllURI = false;

    @Note("是否允许所有的客户端 IP 对服务进行请求。默认关闭")
    private boolean allowAllIPRequest = false;

    @Note("是否禁止所有的客户端 IP 对服务进行请求。默认关闭")
    private boolean denyAllIPRequest = false;

    public JedisClusterPlusGetawayFilter(JedisClusterPlus cache, GetawaySource source) {
        super(source, cache != null, "JedisPlusCluster 客户端实例不能为 null");
        this.cache = cache;
    }

    @Override
    protected Logger protected_getLogger() {
        return LOGGER;
    }

    @Override
    protected Timeunit protected_getImplSelfTimeunit() {
        return Timeunit.SECOND;
    }

    @Override
    protected void protected_putInitProxyWhitesData(Set<String> proxyIps) {
        String key = this.getProxyWhitesCacheKey();
        this.cache.sadd(key, proxyIps);
        this.cache.jedisCluster().srem(key, "");
    }

    @Override
    protected void protected_putInitDisabledURIData(Set<String> disabledURIs) {
        String key = this.getDisableURICacheKey();
        this.cache.sadd(key, disabledURIs);
        this.cache.jedisCluster().srem(key, "");
    }

    @Override
    protected void protected_putInitIPWhitesData(Set<String> ipWhites) {
        String key = this.getIpWhitesCacheKey();
        this.cache.sadd(key, ipWhites);
        this.cache.jedisCluster().srem(key, "");
    }

    @Override
    protected void protected_putInitIPBlacksData(Set<String> ipBlacks) {
        String key = this.getIpBlacksCacheKey();
        this.cache.sadd(key, ipBlacks);
        this.cache.jedisCluster().srem(key, "");
    }

    @Override
    protected Integer protected_getRequestedCount(String key) {
        String s = this.cache.jedisCluster().get(key);
        return (s == null) ? null : Integer.parseInt(s);
    }

    @Override
    protected void protected_setRequestedCount(String key, int requestedCount, long expiration) {
        this.cache.jedisCluster().setex(key, expiration, Integer.toString(requestedCount));
    }

    @Override
    protected void protected_removeRequestedCountEntry(String key) {
        this.cache.jedisCluster().del(key);
    }

    @Override
    protected long protected_getRemainder(String key) {
        return this.cache.ttl(key);
    }

    @Override
    public boolean isInProxyWhites(String remoteAddr) {
        if(openAllRequest) return true;
        Boolean result = this.cache.jedisCluster().sismember(this.getProxyWhitesCacheKey(), remoteAddr);
        return result != null && result;
    }

    @Override
    public boolean isDisabledURI(String uri) {
        if(disabledAllURI) return true;
        Boolean result = this.cache.jedisCluster().sismember(this.getDisableURICacheKey(), uri);
        return result != null && result;
    }

    @Override
    public boolean isWhitesIP(String clientIP) {
        if(allowAllIPRequest) return true;
        Boolean result = this.cache.jedisCluster().sismember(this.getIpWhitesCacheKey(), clientIP);
        return result != null && result;
    }

    @Override
    public boolean isBlacksIP(String clientIP) {
        if(denyAllIPRequest) return true;
        Boolean result = this.cache.jedisCluster().sismember(this.getIpBlacksCacheKey(), clientIP);
        return result != null && result;
    }

    @Override
    public void addInProxyIPs(String remoteAddr) {
        if(proxyIsEnabled()) {
            boolean result = private_add(this.getProxyWhitesCacheKey(), remoteAddr);
            if(result) this.openAllRequest = true;
        }
    }


    @Override
    public void removeFromProxyIPs(String remoteAddr) {
        if(proxyIsEnabled()) {
            boolean result = private_remove(this.getProxyWhitesCacheKey(), remoteAddr);
            if(result) this.openAllRequest = false;
        }
    }

    @Override
    public void clearProxyIPs() {
        if(proxyIsEnabled()) {
            this.cache.jedisCluster().del(this.getProxyWhitesCacheKey());
        }
    }

    @Override
    public Set<String> copyProxyIPs() {
        return proxyIsEnabled() ? this.cache.jedisCluster().smembers(this.getProxyWhitesCacheKey()) : new HashSet<>();
    }

    @Override
    public boolean proxyIPsIsEmpty() {
        return !proxyIsEnabled() || this.cache.jedisCluster().scard(this.getProxyWhitesCacheKey()) == 0;
    }

    @Override
    public void debugProxyIPs() {
        this.protected_logPrintInitDataList(this.protected_getLogger(), this.copyProxyIPs(), "代理服务器 IP 白名单");
    }

    @Override
    public void addInDisabledURIs(String uri) {
        if(disabledURIIsEnabled()) {
            boolean result = private_add(this.getDisableURICacheKey(), uri);
            if(result) this.disabledAllURI = true;
        }
    }

    @Override
    public void removeFromDisabledURIs(String uri) {
        if(disabledURIIsEnabled()) {
            boolean result = private_remove(this.getDisableURICacheKey(), uri);
            if(result) this.disabledAllURI = false;
        }
    }

    @Override
    public void clearDisabledURIs() {
        if(disabledURIIsEnabled()) {
            this.cache.jedisCluster().del(this.getDisableURICacheKey());
        }
    }

    @Override
    public Set<String> copyDisabledURIs() {
        return disabledURIIsEnabled() ? this.cache.jedisCluster().smembers(this.getDisableURICacheKey()) : new HashSet<>();
    }

    @Override
    public boolean disabledURIsIsEmpty() {
        return !disabledURIIsEnabled() || this.cache.jedisCluster().scard(this.getDisableURICacheKey()) == 0;
    }

    @Override
    public void debugDisabledURIs() {
        this.protected_logPrintInitDataList(this.protected_getLogger(), this.copyDisabledURIs(), "已禁用的接口列表");
    }

    @Override
    public void addInWhites(String clientIP) {
        if(ipWhitesIsEnabled()) {
            boolean result = private_add(this.getIpWhitesCacheKey(), clientIP);
            if(result) this.allowAllIPRequest = true;
        }
    }

    @Override
    public void removeFromWhites(String clientIP) {
        if(ipWhitesIsEnabled()) {
            boolean result = private_remove(this.getIpWhitesCacheKey(), clientIP);
            if(result) this.denyAllIPRequest = false;
        }
    }

    @Override
    public void clearWhites() {
        if(ipWhitesIsEnabled()) {
            this.cache.jedisCluster().del(this.getIpWhitesCacheKey());
        }
    }

    @Override
    public Set<String> copyWhites() {
        return ipWhitesIsEnabled() ? this.cache.jedisCluster().smembers(this.getIpWhitesCacheKey()) : new HashSet<>();
    }

    @Override
    public boolean ipWhitesIsEmpty() {
        return !ipWhitesIsEnabled() || this.cache.jedisCluster().scard(this.getIpWhitesCacheKey()) == 0;
    }

    @Override
    public void debugIPWhites() {
        this.protected_logPrintInitDataList(this.protected_getLogger(), this.copyWhites(), "客户端 IP 白名单");
    }

    @Override
    public void addInBlacks(String clientIP) {
        if(ipBlacksIsEnabled()) {
            boolean result = private_add(this.getIpBlacksCacheKey(), clientIP);
            if(result) this.denyAllIPRequest = true;
        }
    }

    @Override
    public void removeFromBlacks(String clientIP) {
        if(ipBlacksIsEnabled()) {
            boolean result = private_remove(this.getIpBlacksCacheKey(), clientIP);
            if(result) this.denyAllIPRequest = false;
        }
    }

    @Override
    public void clearBlacks() {
        if(ipBlacksIsEnabled()) {
            this.cache.jedisCluster().del(this.getIpBlacksCacheKey());
        }
    }

    @Override
    public Set<String> copyBlacks() {
        return ipBlacksIsEnabled() ? this.cache.jedisCluster().smembers(this.getIpBlacksCacheKey()) : new HashSet<>();
    }

    @Override
    public boolean ipBlacksIsEmpty() {
        return !ipBlacksIsEnabled() || this.cache.jedisCluster().scard(this.getIpBlacksCacheKey()) == 0;
    }

    @Override
    public void debugIPBlacks() {
        this.protected_logPrintInitDataList(this.protected_getLogger(), this.copyBlacks(), "客户端 IP 黑名单");
    }


    @Note("判断添加的内容是否是影响全局的通配符，如果是则修改全局的属性为 true")
    private boolean private_add(String key, String s) {
        if("*".equals(s)) {
            return true;
        }
        if(s != null && !s.isEmpty()) {
            this.cache.jedisCluster().sadd(key, s);
        }
        return false;
    }

    @Note("判断移除的内容是否是影响全局的通配符，如果是则修改全局的属性为 false")
    private boolean private_remove(String key, String s) {
        if("*".equals(s)) {
            return true;
        }
        this.cache.jedisCluster().srem(key, s);
        return false;
    }
}
